import timeit
from memory_profiler import memory_usage

from blockchain.block import Block
from api.datas.data_api import *


class Chain(object):

    def __init__(self, node_id=1):
        self.node_id = node_id
        blocks = get_block()
        if not blocks:
            genesis = Block.genesis()
            insert_block(genesis.to_dict())
            self._chain_list = [genesis]
        else:
            self._chain_list = []
            for b in blocks:
                self._chain_list.append(Block(index=b['index'], nonce=b['nonce'], previous_hash=b['previous_hash'],
                                              data=b['data'], hash=b['hash'],timestamp=b['timestamp'],
                                              create_time=['create_time'], gas_fee=b.get('gas_fee', ''),
                                              node=b.get('node_id', 1),))
        self._difficulty = 4

    def mine(self, data):
        start_time = timeit.default_timer()
        mem_before = memory_usage()[0]

        previous = self._latest_block
        nonce = 0
        while True:
            nonce += 1
            new = Block(previous.index + 1, nonce, previous.hash, data)
            if self._is_hash_valid(new.hash):
                end_time = timeit.default_timer()
                mem_after = memory_usage()[0]
                t = int((end_time - start_time) * 1000)
                m = int((mem_after - mem_before) * 1024 * 1024) or 1
                new.gas_fee = str(t) + '*' + str(
                    m) + 'gas fee'
                new.node = self.node_id
                insert_block(new.to_dict())
                self._chain_list.append(new)
                return new

    def replace_chain(self, chain):
        if len(chain) > len(self._chain_list):
            chain_list = []
            for block in chain:
                chain_list.append(Block(
                    int(block['index']), int(block['nonce']),
                    block['previous_hash'], block['data'], block['hash'],
                    float(block['timestamp'])))
            self._chain_list = chain_list

    def to_dict(self):
        return [item.to_dict() for item in self._chain_list]

    def _is_hash_valid(self, hash):
        return hash[:self._difficulty] == '0' * self._difficulty

    @property
    def _latest_block(self):
        return self._chain_list[-1]

    def add_chain_only(self, data):
        self._chain_list.append(data)


if __name__ == '__main__':
    c=Chain()
    print(len(c._chain_list))
